﻿using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace CAN_Controller
{
    public partial class MainForm : Form
    {
        /// <summary>
        /// 记录是否打开了设备，全局唯一变量
        /// </summary>
        public static bool isOpenedDrive = false;
        /// <summary>
        /// 初始化的设置
        /// </summary>
        public static VCI_INIT_CONFIG mConfig;
        /// <summary>
        /// 设备类型 USBCAN USBCAN2 USBCAN2A 都为4
        /// </summary>
        public static uint mDevType = 4;
        /// <summary>
        /// 设备索引号 默认 0
        /// </summary>
        public static uint mDevIndex = 0;
        /// <summary>
        /// 通道号
        /// </summary>
        public static uint mCANIndex = 0;
        /// <summary>
        /// 帧ID。32 位变量，数据格式为靠右对齐。
        /// </summary>
        public static uint mFlagID = 0;
        /// <summary>
        /// 发送帧类型。
        ///=0 时为正常发送（发送失败会自动重发，重发最长时间为1.5-3 秒）；
        ///=1 时为单次发送（只发送一次，不自动重发）；
        ///=2 时为自发自收（自测试模式，用于测试CAN 卡是否损坏）；
        ///=3 时为单次自发自收（单次自测试模式，只发送一次）。
        ///只在此帧为发送帧时有意义。
        /// </summary>
        public static uint mSendType = 0;
        /// <summary>
        /// 是否是远程帧。=0 时为为数据帧，=1 时为远程帧（数据段空）。
        /// </summary>
        public static uint mRemoteFlag = 0;
        /// <summary>
        /// 是否是扩展帧。=0 时为标准帧（11 位ID），=1 时为扩展帧（29 位ID）。
        /// </summary>
        public static uint mExternFlag = 0;
        /// <summary>
        ///数据长度DLC(小于等于8)，即CAN 帧Data 有几个字节。约束了后面Data[8]中的有效字节
        /// </summary>
        public static uint mLen = 8;

        //发送的数据  第一个字节为ID 第二个字节为命令
        //01 02 03 04 05 06 07 
        //使用时要加ID 如： "01" + Str_open_x = "01 00 02 03 04 05 06 07 "
        static string Str_open_1 = " 11 02 03 04 05 06 07 ";
        static string Str_open_1_2 = " 12 02 03 04 05 06 07 ";
        static string Str_open_1_4 = " 14 02 03 04 05 06 07 ";
        static string Str_close_x = " FF 02 03 04 05 06 07 ";

        public MainForm()
        {
            InitializeComponent();
            //这里修改初始化时候的数量,循环一次往里面加一个小面板
            for (int i = 1; i <= 30; i++)
            {
                mainLayoutPanel.Controls.Add(new MachinePanel(i));
            }
            //初始化 VCI_INIT_CONFIG
            mConfig = new VCI_INIT_CONFIG();
            mConfig.AccCode = 0x00000000;//验收码
            mConfig.AccMask = 0xFFFFFFFF;//0xFFFFFFFF，即全部接收
            mConfig.Filter = 1;//=1 表示单滤波，=0 表示双滤波
            mConfig.Timing0 = 0x03; //125Kbps 0x03
            mConfig.Timing1 = 0x1C; //125Kbps 0x1C
            mConfig.Mode = 0;//=0 表示正常模式，=1 表示只听模式
        }

        unsafe private void MenuItem_Click(object sender, EventArgs e)
        {
            switch (((ToolStripMenuItem)sender).Tag.ToString())
            {
                case "open_all":
                    {
                        mFlagID = 0;
                        if (sendMsg("FF", "open", "全部打开错误！") == false)
                            return;
                        //改变UI
                        foreach (MachinePanel mp in mainLayoutPanel.Controls)
                        {
                            mp.openUI();
                            mp.changeSelect(0);
                        }
                    }
                    break;
                case "close_all":
                    {
                        mFlagID = 0;
                        if (sendMsg("FF", "close", "全部关闭错误！") == false)
                            return;
                        //改变UI
                        foreach (MachinePanel mp in mainLayoutPanel.Controls)
                        {
                            mp.closeUI();
                        }
                    }
                    break;
                case "machine_num":
                    {
                        DialogForm dialog = new DialogForm("请输入数量！", "数量：");
                        if (dialog.ShowDialog() == DialogResult.OK)
                        {
                            int num = -1;
                            try
                            {
                                num = int.Parse(dialog.Result);
                            }
                            catch (Exception exception)
                            {
                                Console.Write(exception.Message);
                            }

                            if (num >= 0)
                            {
                                //清除所有面板
                                mainLayoutPanel.Controls.Clear();

                                for (int i = 1; i <= num; i++)
                                {
                                    mainLayoutPanel.Controls.Add(new MachinePanel(i));
                                }
                            }
                        }
                    }
                    break;
                case "drive_setting":
                    {
                        SettingsForm form = new SettingsForm();
                        form.Show();
                    }
                    break;
                case "open_drive":
                    {
                        //if (isOpenedDrive == false)
                        //{
                        if (ExternalLib.VCI_OpenDevice(mDevType, mDevIndex, 0) == 1)
                        {
                            //初始化并打开设备0通道0            mCANIndex默认为零 
                            if (ExternalLib.VCI_InitCAN(mDevType, mDevIndex, mCANIndex, ref mConfig) == 0)
                                Console.WriteLine("0 init fail");
                            if (ExternalLib.VCI_StartCAN(mDevType, mDevIndex, mCANIndex) == 0)
                                Console.WriteLine("0 start fail");
                            //初始化并打开设备0通道1
                            if (ExternalLib.VCI_InitCAN(mDevType, mDevIndex,/*CANIndex*/ 1, ref mConfig) == 0)
                                Console.WriteLine("1 init fail");
                            if (ExternalLib.VCI_StartCAN(mDevType, mDevIndex,/*CANIndex*/ 1) == 0)
                                Console.WriteLine("1 start fail");

                            isOpenedDrive = true;
                            open_Menu.Text = "设备(此时：开)";
                            timer_receive.Enabled = true;
                        }
                        else
                        {
                            MessageBox.Show("打开设备失败,请检查设备类型和设备索引号是否正确", "错误",
                            MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        }
                        //}
                        //else
                        //{
                        //    MessageBox.Show("设备已经打开！", "警告",
                        //        MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        //}
                    }
                    break;
                case "close_drive":
                    {
                        //if (isOpenedDrive == true)
                        //{
                        ExternalLib.VCI_CloseDevice(mDevType, mDevIndex);
                        open_Menu.Text = "设备(此时：关)";
                        isOpenedDrive = false;
                        //}
                    }
                    break;
                default: break;
            }
        }

        private void formClosed(object sender, FormClosedEventArgs e)
        {
            //if (isOpenedDrive == true)
            try
            {
                ExternalLib.VCI_CloseDevice(mDevType, mDevIndex);
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message);
            }
        }

        unsafe private void receive(object sender, EventArgs e)
        {
            if (ExternalLib.VCI_GetReceiveNum(mDevType, mDevIndex,/*CANIndex*/ 1) == 0)
                return;

            Console.WriteLine("Flag!");
            uint con_maxlen = 50;
            IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(VCI_CAN_OBJ)) * (Int32)con_maxlen);

            //VCI_CAN_OBJ[] objP = new VCI_CAN_OBJ[100];
            //实际读到的帧数
            uint returnedFlagNums = ExternalLib.VCI_Receive(mDevType, mDevIndex, /*CANIndex*/1, pt, con_maxlen, 100);

            string result = "";
            for (uint i = 0; i < returnedFlagNums; i++)
            {
                VCI_CAN_OBJ obj = (VCI_CAN_OBJ)Marshal.PtrToStructure((IntPtr)((UInt32)pt + i * Marshal.SizeOf(typeof(VCI_CAN_OBJ))), typeof(VCI_CAN_OBJ));
                //VCI_CAN_OBJ obj = objP[i];
                result = "接收到数据: ";
                result += "  帧ID:0x" + Convert.ToString((Int32)obj.ID, 16);
                result += "  帧格式:";
                if (obj.RemoteFlag == 0)
                    result += "数据帧 ";
                else
                    result += "远程帧 ";
                if (obj.ExternFlag == 0)
                    result += "标准帧 ";
                else
                    result += "扩展帧 ";

                if (obj.RemoteFlag == 0)
                {
                    result += "数据: ";
                    byte len = (byte)(obj.DataLen % 9);
                    byte j = 0;
                    while (j < len)
                    {
                        string str = Convert.ToString(obj.Data[j], 16);
                        if (str.Length == 1)
                            str = "0" + str;
                        result += " " + str;
                        j++;
                    }
                }
            }
            Console.WriteLine(result);
            MessageBox.Show(result, "接收到的数据：", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            Marshal.FreeHGlobal(pt);
        }

        unsafe static public bool sendMsg(string ID, string mode, string errorTxt = "")
        {
            if (isOpenedDrive == false)
            {
                MessageBox.Show("请先打开设备！", "警告",
                MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return false;
            }
            //初始化发送的对象
            VCI_CAN_OBJ sendObj = new VCI_CAN_OBJ();
            sendObj.ID = mFlagID;// =0  帧ID
            sendObj.SendType = (byte)mSendType; // = 0 时为正常发送
            sendObj.RemoteFlag = (byte)mRemoteFlag;// =0 时为为数据帧
            sendObj.ExternFlag = (byte)mExternFlag;//=0 时为标准帧（11 位ID）
            sendObj.DataLen = (byte)mLen;// = 8 Data 有8个字节

            //把 ID 和数据整合起来 即 "ID"+" 00(FF) 02 03 04 05 06 07"
            string str_send = null;
            if (mode.Equals("open"))
            {
                str_send = ID + Str_open_1;
            }
            else if (mode.Equals("open1_2"))
            {
                str_send = ID + Str_open_1_2;
            }
            else if (mode.Equals("open1_4"))
            {
                str_send = ID + Str_open_1_4;
            }
            else if (mode.Equals("close"))
            {
                str_send = ID + Str_close_x;
            }

            Console.WriteLine(str_send);
            for (int i = 0; i < 8 && !str_send.Equals(null); i++)
            {
                ////////////////////////////////////////在这里改要发送的字符串 str_send
                sendObj.Data[i] = Convert.ToByte("0x" + str_send.Substring(i * 3, 2), 16);
            }

            if (ExternalLib.VCI_Transmit(mDevType, mDevIndex, mCANIndex, ref sendObj, 1) == 0)
            {
                MessageBox.Show(errorTxt, "错误",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            return true;
        }
        ////命名空间////
    }
}
